﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StunEngine.Rendering;
using Microsoft.Xna.Framework.Content;

namespace StunEngine.Effects
{
    /// <summary>
    /// 对实现法线映射的NormalMapping.fx的封装。
    /// </summary>
    public class NormalMappingEffect : DiffuseLightEffectWrapper
    {              
        // Effect参数
        EffectParameter specularColorParam;
        EffectParameter specularPowerParam;
        EffectParameter diffuseTextureParam;
        EffectParameter diffuseTextureUVTileParam;
        EffectParameter detailTextureParam;
        EffectParameter detailTextureUVTileParam;

        /// <summary>
        /// 获取或设置镜面高光颜色。
        /// </summary>
        public Vector3 SpecularColor
        {
            get { return specularColorParam.GetValueVector3(); }
            set { specularColorParam.SetValue(value); }
        }

        /// <summary>
        /// 获取或设置镜面高光强度。
        /// </summary>
        public float SpecularPower
        {
            get { return specularPowerParam.GetValueSingle(); }
            set { specularPowerParam.SetValue(value); }
        }

        /// <summary>
        /// 获取或设置漫反射纹理。
        /// </summary>
        public Texture2D DiffuseTexture
        {
            get { return diffuseTextureParam.GetValueTexture2D(); }
            set { diffuseTextureParam.SetValue(value); }
        }

        /// <summary>
        /// 获取或设置漫反射纹理的平铺次数。
        /// </summary>
        public Vector2 DiffuseTextureUVTile
        {
            get { return diffuseTextureUVTileParam.GetValueVector2(); }
            set { diffuseTextureUVTileParam.SetValue(value); }
        }
        
        /// <summary>
        /// 获取或设置法线贴图
        /// </summary>
        public Texture2D DetailTexture
        {
            get { return detailTextureParam.GetValueTexture2D(); }
            set { detailTextureParam.SetValue(value); }
        }

        /// <summary>
        /// 获取或设置法线贴图的平铺次数
        /// </summary>
        public Vector2 DetailTextureUVTile
        {
            get { return detailTextureUVTileParam.GetValueVector2(); }
            set { detailTextureUVTileParam.SetValue(value); }
        }                

        /// <summary>
        /// 创建一个NormalMappingEffect对象。
        /// </summary>
        public NormalMappingEffect(): base(StunXnaGE.NormalMappingEffect){}        
        
        /// <summary>
        /// 缓存effect的参数，重写了基类方法。
        /// </summary>
        protected override void CacheEffectParameters()
        {
            worldParam = effect.Parameters["World"];
            worldViewProjParam = effect.Parameters["WorldViewProj"];
            eyePositionParam = effect.Parameters["EyePosition"];

            clipPlaneEnabledParam = effect.Parameters["ClipPlaneEnabled"];
            clipPlaneParam = effect.Parameters["ClipPlane"];        

            diffuseTextureParam = effect.Parameters["DiffuseTexture"];
            diffuseTextureUVTileParam = effect.Parameters["DiffuseTextureUVTile"];
            detailTextureParam = effect.Parameters["DetailTexture"];
            detailTextureUVTileParam = effect.Parameters["DetailTextureUVTile"];
            
            specularColorParam = effect.Parameters["SpecularColor"];
            specularPowerParam = effect.Parameters["SpecularPower"];
            diffuseColorParam = effect.Parameters["DiffuseColor"];
            emissiveColorParam = effect.Parameters["EmissiveColor"];

            fogColorParam = effect.Parameters["FogColor"];
            fogVectorParam = effect.Parameters["FogVector"];

            shaderIndexParam = effect.Parameters["ShaderIndex"];

            light0Param = effect.Parameters["Lights"].Elements[0];
            light1Param = effect.Parameters["Lights"].Elements[1];
            light2Param = effect.Parameters["Lights"].Elements[2];            
        }

        public override void OnApply()
        {
            // 重新计算world矩阵
            if ((dirtyFlags & EffectDirtyFlags.World) != 0)
            {
                worldParam.SetValue(world);
            }
            
            // 重新计算world+view+projection矩阵或雾化矢量
            dirtyFlags = EffectHelpers.SetWorldViewProjAndFog(dirtyFlags, ref world, ref view, ref projection, ref worldView, fogEnabled, fogStart, fogEnd, worldViewProjParam, fogVectorParam);

            /// 重新计算diffuse/emissive/alpha材质的颜色参数。
            if ((dirtyFlags & EffectDirtyFlags.MaterialColor) != 0)
            {
                Vector4 diffuse = new Vector4();
                Vector3 emissive = new Vector3();
                
                diffuse.X = diffuseColor.X * alpha;
                diffuse.Y = diffuseColor.Y * alpha;
                diffuse.Z = diffuseColor.Z * alpha;
                diffuse.W = alpha;
                
                emissive.X = (emissiveColor.X + ambientLightColor.X * diffuseColor.X) * alpha;
                emissive.Y = (emissiveColor.Y + ambientLightColor.Y * diffuseColor.Y) * alpha;
                emissive.Z = (emissiveColor.Z + ambientLightColor.Z * diffuseColor.Z) * alpha;
                
                diffuseColorParam.SetValue(diffuse);
                emissiveColorParam.SetValue(emissive);

                dirtyFlags &= ~EffectDirtyFlags.MaterialColor; 
            }
            // 重新设置shader index参数
            if ((dirtyFlags & EffectDirtyFlags.ShaderIndex) != 0)
            {
                int shaderIndex = 0;

                if (fogEnabled)
                    shaderIndex += 1;

                shaderIndexParam.SetValue(shaderIndex);

                dirtyFlags &= ~EffectDirtyFlags.ShaderIndex;
            }
        }
    }
}